﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.IO;

namespace ChatClientApp.Classes
{
    
    class ListeningServer
    {
        TcpListener chatServer;
        System.IO.StreamReader reader;
        System.IO.StreamWriter writer;
        BackgroundWorker bwServer;
        public delegate void ReceivedMessageEventHandler(object sender, ChatMessage msg);
        public delegate void ReceivedFileMessageEventHandler(object sender, ChatFileMessage fMsg);
        public static event ReceivedMessageEventHandler OnReceivedMessageHandler;
        public static event ReceivedFileMessageEventHandler OnReceivedFileMessageHandler;

        public ListeningServer(int port)
        {
            bwServer = new BackgroundWorker();
            bwServer.DoWork += new DoWorkEventHandler(bwServer_DoWork);
            bool isAvailable = true;

            IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipEndPoints = ipGlobalProperties.GetActiveTcpListeners();
            TcpConnectionInformation[] tcpConnInfoArray = ipGlobalProperties.GetActiveTcpConnections();

            foreach (TcpConnectionInformation tcpi in tcpConnInfoArray)
            {
                if (tcpi.LocalEndPoint.Port == port)
                {
                    isAvailable = false;
                    break;
                }
            }

            if (!isAvailable)
            {
                throw new Exception("PORT USED");
            }

            foreach (IPEndPoint ipep in ipEndPoints)
            {
                if (ipep.Port == port)
                {
                    isAvailable = false;
                    break;
                }
            }

            if (!isAvailable)
            {
                throw new Exception("PORT USED");
            }

            chatServer = new TcpListener(IPAddress.Any, port);
            bwServer.RunWorkerAsync();

        }

        private void bwServer_DoWork(object sender, DoWorkEventArgs e)
        {
            while (true)
            {
                chatServer.Start();
                if (chatServer.Pending())
                {
                    TcpClient chatConnection = chatServer.AcceptTcpClient();
                    startChat(chatConnection);
                }
                System.Threading.Thread.Sleep(1000);
            }
        }

        public void startChat(TcpClient chatConnection)
        {
            System.IO.StreamWriter writer = new System.IO.StreamWriter(chatConnection.GetStream());
            System.IO.StreamReader reader = new System.IO.StreamReader(chatConnection.GetStream());
            string temp = reader.ReadLine();
            switch (temp)
            {
                case "MESSAGE":
                    readMessage(chatConnection, writer, reader);
                    break;
                case "FILE":
                    // readFile(chatConnection, writer, reader);
                    readFile(chatConnection);
                    break;
                default:
                    break;
            }
        }

        private void readMessage(TcpClient chatConnection, System.IO.StreamWriter writer, System.IO.StreamReader reader)
        {
            List<string> messageRead = new List<string>();
            writer.WriteLine("ACK");
            writer.Flush();
            string nick = reader.ReadLine();
            string mess = reader.ReadLine();

            while (mess != "FINISHED")
            {
                messageRead.Add(mess);
                mess = reader.ReadLine();
            }

            string[] message = messageRead.ToArray();
            ChatMessage msg = new ChatMessage(nick, message, (IPEndPoint)chatConnection.Client.RemoteEndPoint);
            raiseEvent(msg);
        }

        public void sendMessage(IPEndPoint sendToUser, string nickNameFrom, string[] message)
        {
            TcpClient tcp = new TcpClient();
            tcp.Connect(sendToUser);
            System.IO.StreamWriter writer = new System.IO.StreamWriter(tcp.GetStream());
            System.IO.StreamReader reader = new System.IO.StreamReader(tcp.GetStream());
            writer.WriteLine("MESSAGE");
            writer.Flush();
            string temp = reader.ReadLine();
            if (temp == "ACK")
            {
                writer.WriteLine(nickNameFrom);
                writer.Flush();

                foreach (string msg in message)
                {
                    writer.WriteLine(msg);
                    writer.Flush();
                }
                writer.WriteLine("FINISHED");
                writer.Flush();
            }
        }

        public void readFile(TcpClient chatConnection)
        {
            NetworkStream stream = chatConnection.GetStream();
            StreamReader sr = new StreamReader(chatConnection.GetStream());
            StreamWriter wr = new StreamWriter(chatConnection.GetStream());

            wr.WriteLine("ACK");
            wr.Flush();

            string nick = sr.ReadLine();
            string filename = sr.ReadLine();
            IPEndPoint endpoint = (IPEndPoint)chatConnection.Client.RemoteEndPoint;
            string datalength = sr.ReadLine();

            byte[] empfang = new byte[Convert.ToInt32(datalength)];

            wr.WriteLine("START");
            wr.Flush();

            stream.Read(empfang, 0, empfang.Length);

            wr.WriteLine("ACK");

            stream.Close();
            string[] temp = new string[] {nick + ": ", "File "+ filename + " received from " + nick + "." };
            
            ChatFileMessage fMsg = new ChatFileMessage(nick, temp, endpoint, empfang, filename);
            raiseEvent(fMsg);

        }

        public void sendFile(string nickNameFrom, string fileToSend, IPEndPoint sendToUser)
        {
            TcpClient tcp = new TcpClient();
            if (!tcp.Connected)
                tcp.Connect(sendToUser);

            NetworkStream netStream = tcp.GetStream();

            StreamWriter sw = new StreamWriter(tcp.GetStream());
            StreamReader sr = new StreamReader(tcp.GetStream());
            sw.WriteLine("FILE");
            sw.Flush();
            string srv_message = sr.ReadLine();

            if (srv_message == "ACK")
            {
                sw.WriteLine(nickNameFrom);
                sw.Flush();
                sw.WriteLine(fileToSend.Substring(fileToSend.LastIndexOf("\\") + 1));
                sw.Flush();
                byte[] data = File.ReadAllBytes(fileToSend);
                sw.WriteLine(data.Length.ToString());
                sw.Flush();

                BinaryWriter bwr = new BinaryWriter(netStream); 
                int i = 0;

                srv_message = sr.ReadLine();

                if (srv_message == "START")
                {
                    bwr.Write(data, 0, data.Length);
                    bwr.Flush();
                }

                srv_message = sr.ReadLine();
                if (srv_message == "ACK")
                {
                    netStream.Close();
                    tcp.Close();
                }
            }
        }

        [Obsolete]
        public void sendFile(IPEndPoint sendToUser, string nickNameFrom, string fileToSend)
        {
            FileStream fs = new FileStream(fileToSend,FileMode.Open);
            TcpClient tcp = new TcpClient();
            tcp.Connect(sendToUser);

            System.Net.Sockets.NetworkStream netStream = tcp.GetStream();
            System.IO.StreamWriter writer = new System.IO.StreamWriter(tcp.GetStream());
            System.IO.StreamReader reader = new System.IO.StreamReader(tcp.GetStream());
            writer.WriteLine("FILE");
            writer.Flush();
            string temp = reader.ReadLine();
            if (temp == "ACK")
            {
                writer.WriteLine(nickNameFrom);
                writer.Flush();

                int length = (int)fs.Length;
                byte[] data = new byte[length];
                fs.Read(data, 0, length);
                fs.Close();


                writer.WriteLine(data.Length);
                writer.Flush();

                writer.WriteLine(fs.Name.Substring(fs.Name.LastIndexOf("\\") + 1));
                writer.Flush();

                if (netStream.CanWrite)
                {
                    int i = 0;
                    while(i < data.Length)
                    {
                        netStream.WriteByte(data[i]);
                        i++;
                    }
                    netStream.Flush();
                }

                temp = reader.ReadLine();

                if (temp == "ACK")
                {
                    writer.WriteLine("FINISHED");
                    writer.Flush();
                }
            }
        }

        [Obsolete]
        public void readFile(TcpClient chatConnection, System.IO.StreamWriter writer, System.IO.StreamReader reader)
        {

            writer.WriteLine("ACK");
            writer.Flush();
            string nick = reader.ReadLine();
            string length = reader.ReadLine();
            string name = reader.ReadLine();

            byte[] data = new byte[Convert.ToInt32(length)];
            char[] buffer = new char[Convert.ToInt32(length)];

            reader.Read(buffer, 0, buffer.Length);

            for (int i = 0; i < data.Length; i++)
            {
                data[i] = (byte)buffer[i];
            }

            writer.WriteLine("ACK");
            writer.Flush();

            string srv_message = reader.ReadLine();
            if (srv_message == "FINISHED")
            {

            }

            string[] temp = new string[] { nick + ": ", "File received." };
            ChatFileMessage fMsg = new ChatFileMessage(nick, temp, (IPEndPoint)chatConnection.Client.RemoteEndPoint, data, name);
            raiseEvent(fMsg);
        }

        [Obsolete]
        public void sendMessage(IPEndPoint sendToUser, string nickNameFrom, string message)
        {
            TcpClient tcp = new TcpClient();
            tcp.Connect(sendToUser);
            System.IO.StreamWriter writer = new System.IO.StreamWriter(tcp.GetStream());
            System.IO.StreamReader reader = new System.IO.StreamReader(tcp.GetStream());
            writer.WriteLine("MESSAGE");
            writer.Flush();
            string temp = reader.ReadLine();
            if (temp == "ACK")
            {
                writer.WriteLine(nickNameFrom);
                writer.WriteLine(message);
                writer.WriteLine("FINISHED");
                writer.Flush();
            }
        }

        void raiseEvent(ChatMessage msg)
        {
            this.OnReceivedMessage(msg);
        }

        void raiseEvent(ChatFileMessage fMsg)
        {
            this.OnReceivedFileMessage(fMsg);
        }

        protected void OnReceivedMessage(ChatMessage msg)
        {
            if (OnReceivedMessageHandler != null)
                OnReceivedMessageHandler(this, msg);
        }

        protected void OnReceivedFileMessage(ChatFileMessage fMsg)
        {
            if (OnReceivedFileMessageHandler != null)
                OnReceivedFileMessageHandler(this, fMsg);
        }
    }
}
